/**
 * @file midi_parser.c
 * @brief MIDI消息解析器实现
 * @date 2025-11-04
 */

#include "midi_parser.h"
#include "midi2_ump.h"
#include "midi2_translator.h"
#include <string.h>

/* 私有函数声明 -------------------------------------------------------------*/
static int parse_midi1_message(uint8_t *data, uint8_t len, midi_message_t *msg);
static int parse_ump_message(uint8_t *data, uint8_t len, midi_message_t *msg);
static int parse_ble_midi_message(uint8_t *data, uint8_t len, midi_message_t *msg);
static bool midi_note_is_for_board(uint8_t note, uint8_t board_id);
static int midi_get_note_range(uint8_t board_id, uint8_t *note_start, uint8_t *note_end);

/* 外部函数实现 -------------------------------------------------------------*/

/**
 * @brief 初始化MIDI解析器
 */
int midi_parser_init(void) {
    return 0;
}

/**
 * @brief 解析MIDI数据
 */
int midi_parser_parse(uint8_t *data, uint8_t len, midi_message_t *msg) {
    if (data == NULL || len == 0 || msg == NULL)
    {
        return -1;
    }

    /* 清空消息结构 */
    memset(msg, 0, sizeof(midi_message_t));

    /* 检测BLE MIDI格式 (以0x80开头) */
    if (len >= 3 && data[0] >= BLE_MIDI_HEADER_MIN)
    {
        if (parse_ble_midi_message(data, len, msg) == 0)
        {
            return 0;
        }
    }

    /* 检测MIDI 2.0 UMP格式 (32位对齐) */
    if (len >= 4 && (len % 4) == 0)
    {
        if (parse_ump_message(data, len, msg) == 0)
        {
            return 0;
        }
    }

    /* 尝试MIDI 1.0字节流解析 */
    return parse_midi1_message(data, len, msg);
}

/**
 * @brief 检查消息是否属于指定板号
 */
bool midi_parser_is_for_board(midi_message_t *msg, uint8_t board_id) {
    if (msg == NULL)
    {
        return false;
    }

    /* 广播消息 (所有板都响应) */
    if (msg->type == MIDI_MSG_ALL_NOTES_OFF ||
        msg->type == MIDI_MSG_TEMP_WARNING ||
        msg->type == MIDI_MSG_SETUP_MODE)
    {
        return true;
    }

    /* 检查音符是否属于该板 */
    if (msg->type == MIDI_MSG_NOTE_ON || msg->type == MIDI_MSG_NOTE_OFF)
    {
        return midi_note_is_for_board(msg->note, board_id);
    }

    return false;
}

/**
 * @brief 将MIDI音符转换为通道号
 */
uint8_t midi_parser_note_to_channel(uint8_t note, uint8_t board_id) {
    uint8_t note_start, note_end;

    if (midi_get_note_range(board_id, &note_start, &note_end) != 0)
    {
        return 0xFF;
    }

    if (note < note_start || note > note_end)
    {
        return 0xFF;
    }

    /* 计算通道号 (0-7) */
    return (note - note_start);
}

/* 私有函数实现 -------------------------------------------------------------*/

/**
 * @brief 解析MIDI 1.0消息
 */
static int parse_midi1_message(uint8_t *data, uint8_t len, midi_message_t *msg) {
    if (len < 2)
    {
        return -1;
    }

    uint8_t status = data[0];
    uint8_t type = status & 0xF0;

    msg->channel = status & MIDI_CHANNEL_MASK;

    /* 音符按下 (9x note velocity) */
    if (type == MIDI_STATUS_NOTE_ON && len >= 3)
    {
        msg->type = MIDI_MSG_NOTE_ON;
        msg->note = data[1];
        msg->velocity = data[2];
        msg->velocity_16 = (uint16_t)data[2] << 9;  /* 7位转16位 */

        /* 处理velocity=0的情况 (等同于Note Off) */
        if (msg->velocity == 0)
        {
            msg->type = MIDI_MSG_NOTE_OFF;
        }

        return 0;
    }

    /* 音符关闭 (8x note any) */
    if (type == MIDI_STATUS_NOTE_OFF && len >= 3)
    {
        msg->type = MIDI_MSG_NOTE_OFF;
        msg->note = data[1];
        msg->velocity = data[2];
        msg->velocity_16 = (uint16_t)data[2] << 9;  /* 7位转16位 */
        return 0;
    }

    /* 控制变化 (Bx cc_num cc_val) */
    if (type == MIDI_STATUS_CONTROL_CHANGE && len >= 3)
    {
        msg->controller = data[1];
        msg->value = data[2];

        /* 全部音符关 (B0 7B 00) */
        if (msg->controller == MIDI_CC_ALL_NOTES_OFF && msg->value == 0x00)
        {
            msg->type = MIDI_MSG_ALL_NOTES_OFF;
            return 0;
        }

        /* 设置模式 (B0 0E xx) */
        if (msg->controller == MIDI_CC_SETUP_MODE)
        {
            msg->type = MIDI_MSG_SETUP_MODE;
            return 0;
        }

        /* 温度警告 (B0 0F 7F) */
        if (msg->controller == MIDI_CC_TEMP_WARNING && msg->value == 0x7F)
        {
            msg->type = MIDI_MSG_TEMP_WARNING;
            return 0;
        }

        msg->type = MIDI_MSG_CONTROL_CHANGE;
        return 0;
    }

    return -1; /* 不支持的消息类型 */
}

/**
 * @brief 解析MIDI 2.0 UMP消息
 */
static int parse_ump_message(uint8_t *data, uint8_t len, midi_message_t *msg) {
    if (len < 4)
    {
        return -1;
    }

    /* 使用新的MIDI 2.0 UMP解析器 */
    midi2_message_t msg2;
    if (midi2_ump_parse(data, len, &msg2) == 0)
    {
        /* 转换MIDI 2.0 → MIDI 1.0格式 */
        return midi2_to_midi1(&msg2, msg);
    }

    return -1; /* UMP解析失败 */
}

/**
 * @brief 解析BLE MIDI消息
 */
static int parse_ble_midi_message(uint8_t *data, uint8_t len, midi_message_t *msg) {
    /* BLE MIDI格式: [Header|Timestamp|MIDI状态|数据...] */
    /* 例如: 80 80 80 3A 00 */

    if (len < 3)
    {
        return -1;
    }

    /* 跳过BLE MIDI头和时间戳, 找到MIDI状态字节 */
    uint8_t offset = 0;

    /* 跳过所有头字节 (>=0x80) */
    while (offset < len && data[offset] >= 0x80)
    {
        offset++;
    }

    if (offset >= len)
    {
        return -1;
    }

    /* 剩余数据作为标准MIDI 1.0消息解析 */
    return parse_midi1_message(&data[offset], len - offset, msg);
}

/**
 * @brief 获取板号对应的MIDI音符范围
 * @param board_id 板号 (1-11)
 * @param note_start 输出: 起始音符
 * @param note_end 输出: 结束音符
 * @return 0成功, -1失败
 */
static int midi_get_note_range(uint8_t board_id, uint8_t *note_start, uint8_t *note_end)
{
    if (note_start == NULL || note_end == NULL)
    {
        return -1;
    }

    /* 板号对应MIDI音符范围表 (参考CLAUDE.md) */
    switch (board_id)
    {
        case 11: *note_start = 0x15; *note_end = 0x1C; break;  /* B11: 1-8 */
        case 10: *note_start = 0x1D; *note_end = 0x24; break;  /* B10: 9-16 */
        case 9:  *note_start = 0x25; *note_end = 0x2C; break;  /* B9: 17-24 */
        case 8:  *note_start = 0x2D; *note_end = 0x34; break;  /* B8: 25-32 */
        case 7:  *note_start = 0x35; *note_end = 0x3C; break;  /* B7: 33-40 */
        case 6:  *note_start = 0x3D; *note_end = 0x44; break;  /* B6: 41-48 */
        case 5:  *note_start = 0x45; *note_end = 0x4C; break;  /* B5: 49-56 */
        case 4:  *note_start = 0x4D; *note_end = 0x54; break;  /* B4: 57-64 */
        case 3:  *note_start = 0x55; *note_end = 0x5C; break;  /* B3: 65-72 */
        case 2:  *note_start = 0x5D; *note_end = 0x64; break;  /* B2: 73-80 */
        case 1:  *note_start = 0x65; *note_end = 0x6C; break;  /* B1: 81-88 */
        default: return -1;
    }

    return 0;
}

/**
 * @brief 检查MIDI音符是否属于指定板号
 * @param note MIDI音符号
 * @param board_id 板号 (1-11)
 * @return true属于, false不属于
 */
static bool midi_note_is_for_board(uint8_t note, uint8_t board_id)
{
    uint8_t note_start, note_end;

    if (midi_get_note_range(board_id, &note_start, &note_end) != 0)
    {
        return false;
    }

    return (note >= note_start && note <= note_end);
}

/******************************** 文件结束 *********************************/
